﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Windows;
using System.Xaml;
using System.Web;
using System.Web.Script.Serialization;
using System.Threading;
using System.IO;

namespace FaceDesktopTagger
{
      public partial class frmTagger : Form
    {

          private FaceRestAPI face;
          private string accessToken;
          private PersonalInfo info;
          delegate void CounterDelegate(int total, int processed,int found);
          delegate void SearchButtonDelegate(bool enabled);
        
        public frmTagger()
        {
            InitializeComponent();
        }

        
        
        static void SearchThread(object _form)
        {

            frmTagger form = (frmTagger)_form;
            List<string> fileNames = new List<string>();
            
            form.ChangeSearchButton(false);
          
            //Check type of search and perform search for .jpg files
            if (form.radIndex.Checked == true)
            {
                fileNames = SearchFiles.Search("",".jpg");
            }
            else if(form.radOther.Checked == true)
            {
               fileNames = SearchFiles.Search(form.fldOther.SelectedPath,".jpg");
            }

            //Update UI
            form.UpdateCount(fileNames.Count,0, 0);
            
            //TODO: Load from config
            int i = 0;
            int found = 0;
            int newWidth = 600;
            int maxHeight = 600;
            
            //Loop through all files
            //TODO: Move looping to a seperate class called Tagger (Not done due to time limitations)
            foreach (string fileName in fileNames)
            {
                //update UI
                form.UpdateCount(fileNames.Count, i, found);
                i++;
                
                //Load Image
                System.Drawing.Image image = System.Drawing.Image.FromFile(fileName);

                //Reset thumbnail
                image.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
                image.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
                
                if (image.Width <= newWidth)
                {
                    newWidth = image.Width;
                }
                
                int newHeight = image.Height * newWidth / image.Width;
                if (newHeight > maxHeight)
                {
                    
                    newWidth = image.Width * maxHeight / image.Height;
                    newHeight = maxHeight;
                }

                Image newImage = image.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero);
                //Must save the file to make it more compatible with the API
                newImage.Save("temp.jpg");
                
                // End resize

                //Recognize Image
                FaceRestAPI.FaceAPI faces = new FaceRestAPI.FaceAPI();
                List<string> uids = new List<string>();
               
                uids.Add(form.info.id + "@facebook.com");
                //Execute recognition API
                faces = form.face.faces_recognize(null, uids, "andreysto", "", "temp.jpg", null, "");

                //Check if the user was found on the photo
                foreach (FaceRestAPI.Tag tag in faces.photos[0].tags)
                {
                    foreach(FaceRestAPI.UID uid in tag.uids)
                    {
                        if (uid.uid==form.info.id+"@facebook.com")
                        {

                            //update UI
                            found++;
                            form.UpdateCount(fileNames.Count, i,found);
                            
                            //Tag the photo

                            FileTagger tagger = new FileTagger(fileName);

                            tagger.AddTag(form.info.name);
                        }
                    }
                }
                
                image.Dispose();
                newImage.Dispose();
                File.Delete("temp.jpg");
                
            }

            form.UpdateCount(fileNames.Count, fileNames.Count, found);
            form.ChangeSearchButton(true);
        }

        void UpdateCount(int total, int processed, int found)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new CounterDelegate(UpdateCount), new object[] { total,processed,found });
                return;
            }
            //all updated in 1 function to make code writting faster
            //TODO: Create seperate functions.
            prgFiles.Maximum = total;
            lblTotalImages.Text = "Searching through " + total.ToString() + " images";
            lblFound.Text = "Found " + found.ToString() + " photo(s) of you";
            prgFiles.Value = processed;

        }
        
        void ChangeSearchButton(bool enabled)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new SearchButtonDelegate(ChangeSearchButton), new object[] { enabled });
                return;
            }
            btnSearch.Enabled = enabled;
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            Thread oThread = new Thread(new ParameterizedThreadStart(SearchThread));
            oThread.IsBackground = true;
            oThread.Start(this);
            //TODO: Add stop button
            //oThread.Join();
           
        }

        private void radIndex_CheckedChanged(object sender, EventArgs e)
        {
            btnBrowse.Visible = false;
            txtPath.Text = "Windows Index";
        }

        private void radOther_CheckedChanged(object sender, EventArgs e)
        {
            btnBrowse.Visible = true;
            txtPath.Text = fldOther.SelectedPath;
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            fldOther.ShowDialog();
            txtPath.Text = fldOther.SelectedPath;
        }

        private void webFacebook_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {

            //Check if the user successfully loged in.
            //BUG. If uses press cancel he is still redirected to this page. 
            if (webFacebook.Url.AbsolutePath == "/connect/login_success.html")
            {
                //Read accessToken from the web control. 
                accessToken = webFacebook.Url.Fragment;
                accessToken = accessToken.Replace("#access_token=","");
                accessToken = accessToken.Split('&')[0]; 
                accessToken = accessToken.Replace("%7C","|");
                         
                //Need to do this that this way because of bugs in IE which doesn't open the page correctly
                HttpWebRequest request = (HttpWebRequest)
                    WebRequest.Create("https://graph.facebook.com/me?access_token=" + accessToken);
                HttpWebResponse response = (HttpWebResponse)
                    request.GetResponse();
                Stream resStream = response.GetResponseStream();
                StringBuilder sb = new StringBuilder();
                byte[] buf = new byte[8192];
                string tempString = null;
                int count = 0;
                do
                {
                    count = resStream.Read(buf, 0, buf.Length);
                    if (count != 0)
                    {
                        tempString = Encoding.ASCII.GetString(buf, 0, count);
                        sb.Append(tempString);
                    }
                }
                while (count > 0);
                
                //parse needed information using the PersonalInfo class
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                info = serializer.Deserialize<PersonalInfo>(sb.ToString());

                //Init the Face API class
                List<string> uids = new List<string>();
                FaceRestAPI.FaceAPI faces = new FaceRestAPI.FaceAPI();
                uids.Add(info.id);
                face = new FaceRestAPI("ffd6a55cb6ceaea72d674012bebb3246", "92433100c75675a3d2ef145c32ea3587", "", false, "json",info.id,accessToken);
                
                //Train on the photos of the user
                faces = face.faces_train(uids, "andreysto", "");
                
                //TODO: Report to the user how many photos was used for training and if the training was successful. 

                //enable buttons; 
                grpSearch.Enabled = true;
                //disable web form;
                webFacebook.AllowNavigation = false;
            }

        }
    }
}
